上回我們提到JavaScript的特性,所以就也整理了一篇原型導向
簡單來說就是沒有class,但仍然有物件導向的特性
(ES6 的 class 不是真的class,它只是語法糖)
這是什麼意思呢?
每個物件生成的時候都會有一個原型(Prototype),透過原型鍵(Prototype chain)的方式可以將物件串起來,就達成物件導向的繼承了
我們看一個例子:
我們如果要生成一個實例的話會這樣寫
function Person(name) { //創建一個person的構造函數
this.name = name;
this.sayHi = function () {
console.log('Hi, I am ' + this.name);
}
}
const p1 = new Person('Joanne'); //new 一個Joanne實例
const p2 = new Person('Ricky'); //new 一個Ricky實例
我們在console就可以看到
Joanne裡有name
和sayHi()
、Ricky裡面也有name
和sayHi()
,他們兩個人裡面的sayHi()
明明再做同一件事,但卻被當成不一樣的函式裝在不同人裡面。
更好懂一點的講法,我們可以拿類別導向來一起說明,可以想像class是組餅乾模具,其中一個sayHi就是一種餅乾模具🍪
(餅乾模具就是這個👇)
只要被它壓的(被他創建的)就會就具備這個能力(進到sayHi就會變成sayHi的樣子),而上面那個例子不是,他是把餅乾模具也複製一組起來,這樣就等於佔了新的一組的空間。
(我也不知道這樣會不會比較好懂一點)
所以為了解決,可以使用Prototype來讓他們共用一個函式
function Person(name) {
this.name = name;
}
// 用Prototype加入sayHi()函式
Person.prototype.sayHi = function () {
console.log('Hi, I am ' + this.name);
};
const p1 = new Person('Joanne');
const p2 = new Person('Ricky');
在console可以看到
我們發現sayHi()
函式跑到[[Prototype]]
了!所有的Person實例就可以共享sayHi()
([[Prototype]]
其實就是原型鏈結,也記作__proto__
)
所以若更動sayHi()
,每個Person都使用sayHi()
時都會更動,因為 sayHi()
是存在於 Person.prototype
上,所有實例共用它。如果你改變 Person.prototype.sayHi
的內容,所有實例的行為都會跟著改變
另外,還有一個特性,它可以連結起來,什麼意思呢?
這延伸了上面的程式碼,我們多創建一個新的結構函式Dog,我希望他也可以有Person的方法,讓他成為一隻像人的狗 🐕
所以希望保有Dog自己的方法,也能有Person的方法
function Dog(name) {
this.name = name;
}
// 這一行建立原型鏈:Dog → Person
Dog.prototype = Object.create(Person.prototype);
// 修正 constructor 指向
Dog.prototype.constructor = Dog;
Dog.prototype.bark = function () {
console.log('Woof!');
};
const d = new Dog('Buddy');
d.sayHi(); // 繼承自 Person 的方法
d.bark(); // 自己定義的方法
Dog.prototype = Object.create(Person.prototype);
這樣做會建立一個以 Person.prototype
為原型的新物件,並指定給 Dog.prototype
,讓 Dog 繼承 Person 的方法。
但這樣會覆蓋掉原本的 constructor
,因此我們通常會再補上一行:
Dog.prototype.constructor = Dog;
console可以看到
在程式碼中手動把Dog與Person之間串了一個原型鏈結(__proto__
),我們不用想的太複雜,其實他就是一層一層往上的
dog.__proto__
裡面找 sayHi
dog.__proto__.__proto__
,也就是 Person.prototype
sayHi()
,執行它他們的關係大概像這樣👇,箭頭就是__proto__
([[Prototype]]
)
https://zh.wikipedia.org/zh-tw/基于原型编程
https://blog.techbridge.cc/2017/04/22/javascript-prototype/
https://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html